
open Common

module type DIM =
sig

  val rows : int
  val cols : int

end

module type T =
sig

  module D : DIM

  type 'a t
  val create : 'a -> 'a t  

  val get : 'a t -> int * int -> 'a
  val set : 'a t -> int * int * 'a -> unit
  val to_string : ('a -> string) -> 'a t -> string
  val print : ('a -> string) -> 'a t -> unit

  module Ops : 
  sig
    val ( % ) : 'a t -> int * int -> 'a  
    val ( <-- ) : 'a t -> int * int * 'a -> unit
  end

end

module S(D : DIM) : T with module D = D =
struct 

  module A = Array'
  module D = D

  type 'a t = 'a array
  
  let create x = A.create (D.rows * D.cols) x

  let get m (r,c) = m.(D.cols * r + c)

  let set m (r,c,x) = m.(D.cols * r + c) <- x

  module Ops =
  struct 
    let ( % ) = get
    let ( <-- ) = set
  end

  open Format
  module S = String

  let to_string p m = 
    let m' = A.to_list m in
    let ms = split_list D.cols m' in
    let ls = map (string_of_list p) ms in
      string_of_list id ls

  let print p m =
    let k = ref 0 in
    begin 
      print_string "<<";
      for i = 0 to D.rows - 1 do
        print_string "| ";
        for j = 0 to D.cols - 1 do
          (print_string (p m.(!k));if j <> D.cols - 1 then print_string ", ");
          incr k
        done;
        print_endline " |";
      done;
      print_endline ">>";
    end

end
